package com.fengstyle.demo.minio.util;

import com.fengstyle.demo.minio.config.MinioConfig;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author yuhf
 */
@Slf4j
@Configuration
public class MonioFileUtil {

    @Resource
    private MinioConfig minioConfig;

    private MinioClient minioClient;

    @Bean
    public MinioClient getMinioClient(){
        MinioClient client = MinioClient.builder()
                .endpoint(minioConfig.getIp(), minioConfig.getPort(), minioConfig.isSecure())
                .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey())
                .build();
        this.minioClient = client;
        return client;
    }

    /**
     * 创建桶
     * @param bucketName 名称
     * @throws Exception 异常
     */
    public void createBucket(String bucketName) throws Exception{
        if(!StringUtils.hasLength(bucketName)){
            throw new RuntimeException("创建桶，名称不能为空");
        }
        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
    }

    /**
     * 创建文件夹
     * @param bucketName 桶
     * @param folderName 文件夹名称
     * @return ObjectWriteResponse
     * @throws Exception 异常
     */
    public ObjectWriteResponse createBucketFolder(String bucketName, String folderName) throws Exception{
        if(!StringUtils.hasLength(bucketName) || !StringUtils.hasLength(folderName)){
            throw new RuntimeException("创建文件夹，桶或文件夹名称不能为空");
        }
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(folderName + "/")
                .stream(new ByteArrayInputStream(new byte[0]), 0, 0)
                .build();
        return minioClient.putObject(args);
    }

    /**
     * 校验桶是否存在
     * @param bucketName 名称
     * @return 是否存在
     * @throws Exception 异常
     */
    public boolean checkBucket(String bucketName) throws Exception{
        if(!StringUtils.hasLength(bucketName)){
            throw new RuntimeException("校验桶，名称不能为空");
        }
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    /**
     * 所有桶列表
     * @return 桶列表
     * @throws Exception 异常
     */
    public List<Bucket> getAllBucket() throws Exception{
        return minioClient.listBuckets();
    }

    /**
     * 获取桶文件列表
     * @param bucketName 名称
     * @param folderName 文件夹
     * @param isDeep 是否递归查询
     * @return 文件列表
     */
    public Iterable<Result<Item>> getBucketAllFile(String bucketName, String folderName, boolean isDeep){
        if(!StringUtils.hasLength(bucketName)){
            throw new RuntimeException("获取桶文件列表，名称不能为空");
        }
        if(!StringUtils.hasLength(folderName)){
            folderName = "";
        }
        return minioClient.listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(StringUtils.hasLength(folderName) ?  folderName + "/" : "")
                        .recursive(isDeep)
                        .build()
        );
    }

    /**
     * 删除桶
     * @param bucketName 名字
     * @throws Exception 异常
     */
    public void deleteBucket(String bucketName) throws Exception{
        if(!StringUtils.hasLength(bucketName)){
            throw new RuntimeException("删除桶，名称不能为空");
        }
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /**
     * 删除文件夹
     * @param bucketName 名字
     * @param fileName 文件名称
     */
    public boolean deleteBucketFile(String bucketName, String fileName) {
        if(!StringUtils.hasLength(bucketName) || !StringUtils.hasLength(fileName)){
            throw new RuntimeException("删除文件夹，桶或文件名称不能为空");
        }
        try {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
            return true;
        } catch (Exception e) {
            log.error("deleteBucketFile error: ", e);
            return false;
        }
    }

    /**
     * 获取文件下载链接
     * @param bucketName 桶
     * @param fileName 文件名
     * @param expires 过期时间
     * @return 下载链接
     * @throws Exception 异常
     */
    public String getFileDownloadUrl(String bucketName, String fileName, Integer expires) throws Exception {
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(fileName)
                        .expiry(expires, TimeUnit.SECONDS)
                .build());
    }

    public ObjectWriteResponse uploadFile(MultipartFile file, String bucketName) throws Exception{
        return uploadFile(file, bucketName, "");
    }

    public ObjectWriteResponse uploadFile(MultipartFile file, String bucketName, String folderName) throws Exception{
        if(file == null || file.isEmpty()){
            throw new RuntimeException("上传的文件不能为空");
        }
        if(!StringUtils.hasLength(bucketName)){
            bucketName = minioConfig.getBucketName();
        }
        if(!checkBucket(bucketName)){
            createBucket(bucketName);
        }
        if(StringUtils.hasLength(folderName)){

        }
        String minioFileName = UUID.randomUUID().toString() + file.getOriginalFilename();
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(StringUtils.hasLength(folderName) ? folderName + "/" + minioFileName : minioFileName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        return minioClient.putObject(args);
    }

    /**
     * 下载文件
     * @param bucketName 桶
     * @param fileName 文件
     * @return 文件
     * @throws Exception 异常
     */
    public GetObjectResponse downloadFile(String bucketName, String fileName) throws Exception{
        if(!StringUtils.hasLength(bucketName) || !StringUtils.hasLength(fileName)){
            throw new RuntimeException("下午文件，桶或文件名不能为空");
        }
        if(!checkBucket(bucketName)){
            throw new RuntimeException("当前桶 " + bucketName + " 不存在");
        }
        return minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(fileName)
                .build());
    }

}
